package com.gyc.game.cchess.model;

import static com.gyc.game.cchess.model.TranspositionTable.exact;
import static com.gyc.game.cchess.model.TranspositionTable.lower_bound;
import static com.gyc.game.cchess.model.TranspositionTable.upper_bound;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import com.gyc.game.cchess.GameView;

public class NegaScout_TT_HH extends SearchEngineAbstract {

	private TranspositionTable transpositionTable;
	private HistoryHeuristic historyHeuristic;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.gyc.game.cchess.model.SearchEngineAbstract#destroy()
	 */
	@Override
	public void destroy() {
		try {
			transpositionTable.destroy();
			transpositionTable = null;

		} catch (Exception e) {
			// TODO: handle exception
		}

		try {
			historyHeuristic.destroy();
			historyHeuristic = null;

		} catch (Exception e) {
		}

	}

	public NegaScout_TT_HH() {
		super();
		transpositionTable = new TranspositionTable();
		historyHeuristic = new HistoryHeuristic();

	}

	@Override
	public ChessMove SearchAGoodMove(ChessBoardBitPlanes position) {

		bestMove = null;
		eveluator.count = 0;
		cachehit = 0;

		bestMoveList.clear();

		try {
			CurPosition = position.copy();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}

		if (transpositionTable == null) {
			System.out.println("null transpositionTable and inited");
			transpositionTable = new TranspositionTable();
		}

		if (historyHeuristic == null) {
			System.out.println("null transpositionTable and inited");
			historyHeuristic = new HistoryHeuristic();
		}

		if (CurPosition == null) {
			System.out.println("null CurPosition and inited");
		}

		transpositionTable.CalculateInitHashKey(CurPosition);

		historyHeuristic.ResetHistoryTable();

		NegaScout(0, -20000, 20000);

		System.out.println("cachehit :" + cachehit + " eveluator.count: "
				+ eveluator.count);

		System.out.println("bestMoveList size:" + bestMoveList.size());

		Collections.reverse(this.bestMoveList);
		List<ChessMove> it = this.bestMoveList;

		for (Iterator<ChessMove> iterator = it.iterator(); iterator.hasNext();) {
			ChessMove chessMove = iterator.next();
			if (CurPosition.isLooping(chessMove, searchDepth)) {
				continue;
			} else {
				return chessMove;
			}
		}

		return null;

	}

	long cachehit;

	int NegaScout(int step, int alpha, int beta) {
		byte type;

		int i = IsGameOver(step);

		if (i != 0) {
			return i;
		}

		boolean isred = (byte) (step % 2) != 0;

		int score = transpositionTable.LookUpHashTable(alpha, beta, step,
				isred ? 1 : 0);

		if (score != transpositionTable.TT_NOT_HIT) {
			cachehit++;
			return score;
		}

		if (step == this.searchDepth) {
			score = eveluator.eveluate(CurPosition, isred);
			transpositionTable
					.EnterHashTable(exact, score, step, isred ? 1 : 0);
			return score;

		}

		if (this.CurPosition.lastMove.chk) {

			int cnt = CurPosition.generatePossibleChkedMoves(isred, step);
			if (cnt == 0) {
				return alpha;
			}

			for (i = 0; i < cnt; i++) {
				final ChessMove chessMoveAtDepth = CurPosition.m_MoveList[step][i];
				chessMoveAtDepth.Score = historyHeuristic
						.GetHistoryScore(chessMoveAtDepth);
			}
			historyHeuristic
					.MergeSort(CurPosition.m_MoveList[step], cnt, false);

			int bestnum = -1;
			int a = alpha;
			int b = beta;
			int eval_is_exact = 0;

			for (i = 0; i < cnt; i++) {
				if (this.getThread().isInterrupted()) {
					break;
				}
				if (step == 0) {
					this.getUihandler()
							.sendEmptyMessage(GameView.message_inter);
				}

				transpositionTable
						.Hash_MakeMove(CurPosition.m_MoveList[step][i]);

				CurPosition.makeMove(CurPosition.m_MoveList[step][i], true);

				int t = -NegaScout(step + 1, -b, -a);

				if (t > a && t < beta && i > 0) {
					a = -NegaScout(step + 1, -beta, -t); /* re-search */
					eval_is_exact = 1;
					if (step == 0) {
						bestMove = CurPosition.m_MoveList[step][i];
						bestMoveList.add(bestMove);
					}

					bestnum = i;
				}

				transpositionTable
						.Hash_UnMakeMove(CurPosition.m_MoveList[step][i]);

				CurPosition.unMakeMove(CurPosition.m_MoveList[step][i]);

				if (a < t) {
					eval_is_exact = 1;
					a = t;
					if (step == 0) {
						bestMove = CurPosition.m_MoveList[step][i];
						bestMoveList.add(bestMove);
					}
				}
				if (a >= beta) {
					transpositionTable.EnterHashTable(lower_bound, a, step,
							isred ? 1 : 0);
					historyHeuristic.EnterHistoryScore(
							CurPosition.m_MoveList[step][i], this.searchDepth
									- step);
					return a;
				}

				b = a + 1; /* set new null window */
			}
			if (bestnum != -1)
				historyHeuristic.EnterHistoryScore(
						CurPosition.m_MoveList[step][bestnum], this.searchDepth
								- step);
			if (eval_is_exact != 0)
				transpositionTable
						.EnterHashTable(exact, a, step, isred ? 1 : 0);
			else
				transpositionTable.EnterHashTable(upper_bound, a, step,
						isred ? 1 : 0);
			return a;

		} else {
			int cnt = CurPosition.generatePossibleMoves(isred, step);

			for (i = 0; i < cnt; i++) {
				final ChessMove chessMoveAtDepth = CurPosition.m_MoveList[step][i];
				chessMoveAtDepth.Score = historyHeuristic
						.GetHistoryScore(chessMoveAtDepth);
			}
			historyHeuristic
					.MergeSort(CurPosition.m_MoveList[step], cnt, false);
			int bestnum = -1;
			int a = alpha;
			int b = beta;
			int eval_is_exact = 0;
			for (i = 0; i < cnt; i++) {
				if (this.getThread().isInterrupted()) {
					break;
				}
				if (step == 0) {
					this.getUihandler()
							.sendEmptyMessage(GameView.message_inter);
				}

				transpositionTable
						.Hash_MakeMove(CurPosition.m_MoveList[step][i]);

				CurPosition.makeMove(CurPosition.m_MoveList[step][i], true);

				int t = -NegaScout(step + 1, -b, -a);

				if (t > a && t < beta && i > 0) {
					a = -NegaScout(step + 1, -beta, -t); /* re-search */
					eval_is_exact = 1;
					if (step == 0) {
						bestMove = CurPosition.m_MoveList[step][i];
						bestMoveList.add(bestMove);
					}

					bestnum = i;
				}

				transpositionTable
						.Hash_UnMakeMove(CurPosition.m_MoveList[step][i]);

				CurPosition.unMakeMove(CurPosition.m_MoveList[step][i]);

				if (a < t) {
					eval_is_exact = 1;
					a = t;
					if (step == 0) {
						bestMove = CurPosition.m_MoveList[step][i];
						bestMoveList.add(bestMove);
					}
				}
				if (a >= beta) {
					transpositionTable.EnterHashTable(lower_bound, a, step,
							isred ? 1 : 0);
					historyHeuristic.EnterHistoryScore(
							CurPosition.m_MoveList[step][i], this.searchDepth
									- step);
					return a;
				}

				b = a + 1; /* set new null window */
			}
			if (bestnum != -1)
				historyHeuristic.EnterHistoryScore(
						CurPosition.m_MoveList[step][bestnum], this.searchDepth
								- step);
			if (eval_is_exact != 0)
				transpositionTable
						.EnterHashTable(exact, a, step, isred ? 1 : 0);
			else
				transpositionTable.EnterHashTable(upper_bound, a, step,
						isred ? 1 : 0);
			return a;

		}

	}

}
